#ifndef VECTOR_H
#define VECTOR_H

#include <math.h>

struct Vector2 {
    double x;
    double y;

    inline Vector2(double x, double y) {
        this->x = x;
        this->y = y;
    }

    inline Vector2() {}

    inline Vector2 operator-() {
        return Vector2(-x, -y);
    }

    inline Vector2 operator+(Vector2 b) {
        return Vector2(x+b.x, y+b.y);
    }

    inline Vector2 operator-(Vector2 b) {
        return Vector2(x-b.x, y-b.y);
    }

    inline Vector2 operator*(double b) {
        return Vector2(x*b, y*b);
    }

    inline Vector2 operator/(double b) {
        return Vector2(x/b, y/b);
    }

    inline double operator*(Vector2 b) {
        return x * b.x + y * b.y;
    }

    inline double magnitude() {
        return sqrt(x*x + y*y);
    }

    inline double operator/(Vector2 b) {
        return this->magnitude() * b.magnitude() - (*this * b);
    }

    inline Vector2 normalize() {
        return (*this = *this / magnitude());
    }
};

struct Vector3 {
    double x;
    double y;
    double z;

    inline Vector3(double x, double y, double z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    inline Vector3() {}

    inline Vector3 operator-() {
        return Vector3(-x, -y, -z);
    }

    inline Vector3 operator+(Vector3 b) {
        return Vector3(x+b.x, y+b.y, z+b.z);
    }

    inline Vector3 operator+=(Vector3 b) {
        return *this = *this + b;
    }

    inline Vector3 operator-(Vector3 b) {
        return Vector3(x-b.x, y-b.y, z-b.z);
    }

    inline Vector3 operator-=(Vector3 b) {
        return *this = *this - b;
    }

    inline Vector3 operator*(double b) {
        return Vector3(x*b, y*b, z*b);
    }

    inline Vector3 operator*=(double b) {
        return *this = *this * b;
    }

    inline Vector3 operator/(double b) {
        return Vector3(x/b, y/b, z/b);
    }

    inline Vector3 operator/=(double b) {
        return *this = *this / b;
    }

    inline double operator*(Vector3 b) {
        return x * b.x + y * b.y + z * b.z;
    }

    inline Vector3 operator/(Vector3 b) {
        return Vector3(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
    }

    inline Vector3 operator/=(Vector3 b) {
        return *this = *this / b;
    }

    inline double magnitude() {
        return sqrt(x*x + y*y + z*z);
    }

    inline Vector3 unit() {
        return *this / magnitude();
    }

    inline Vector3 normalize() {
        return *this = this->unit();
    }
};

struct Matrix3 {
    Vector3 x;
    Vector3 y;
    Vector3 z;

    inline Matrix3(double xx, double xy, double xz, double yx, double yy, double yz, double zx, double zy, double zz) {
        x.x = xx;
        x.y = xy;
        x.z = xz;
        y.x = yx;
        y.y = yy;
        y.z = yz;
        z.x = zx;
        z.y = zy;
        z.z = zz;
    }

    inline Matrix3(Vector3 x, Vector3 y, Vector3 z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    inline Matrix3(double pitch, double yaw) {
        double cx = cos(pitch);
        double cy = cos(yaw);
        double sx = sin(pitch);
        double sy = sin(yaw);
        *this = Matrix3(cy, sy*sx, sy*cx, 0, cx, -sx, -sy, cy*sx, cy*cx);
    }

    inline Matrix3() {}

    inline Matrix3 operator-() {
        return Matrix3(-x, -y, -z);
    }

    inline Matrix3 operator+(Matrix3 b) {
        return Matrix3(x + b.x, y + b.y, z + b.z);
    }

    inline Matrix3 operator-(Matrix3 b) {
        return Matrix3(x - b.x, y - b.y, z - b.z);
    }

    inline Matrix3 operator*(Matrix3 b) {
        return Matrix3(
                x * Vector3(b.x.x, b.y.x, b.z.x), x * Vector3(b.x.y, b.y.y, b.z.y), x * Vector3(b.x.z, b.y.z, b.z.z),
                y * Vector3(b.x.x, b.y.x, b.z.x), y * Vector3(b.x.y, b.y.y, b.z.y), y * Vector3(b.x.z, b.y.z, b.z.z),
                z * Vector3(b.x.x, b.y.x, b.z.x), z * Vector3(b.x.y, b.y.y, b.z.y), z * Vector3(b.x.z, b.y.z, b.z.z));
    }

    inline Matrix3 operator+=(Matrix3 b) {
        return *this = *this + b;
    }

    inline Matrix3 operator-=(Matrix3 b) {
        return *this = *this - b;
    }

    inline Matrix3 operator*=(Matrix3 b) {
        return *this = *this * b;
    }

    inline Vector3 operator*(Vector3 b) {
        return Vector3(x * b, y * b, z * b);
    }
};

#endif // VECTOR_H


